#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QComboBox"
#include "QDebug"
#include "QProgressBar"
#include "QLabel"
#include "QFont"
#include "QApplication"
#include <QAxObject>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

   //openAction = new QAction(QIcon(":/images/doc-open"), "打开", this);
  //openAction->setShortcuts(QKeySequence::Open);
  //openAction->setStatusTip(tr("Open an existing file"));
  //connect(openAction, SIGNAL(triggered()), this, SLOT(open()));

    menuBar()->addMenu(tr("&BBI"));

    //file->addAction(openAction);
    //QToolBar *toolBar = addToolBar(tr("&File"));
    //toolBar->addAction(openAction);

    this->setFixedSize( this->width (),this->height ());

    // 定时器溢出信号 --> 连接到槽函数
    QObject::connect(&TIME1, &QTimer::timeout, this, &MainWindow::timer_slots_IRQHandler);
    QObject::connect(&TIME2, &QTimer::timeout, this, &MainWindow::timer2_slots_IRQHandler);

    //串口接收连接 槽函数
    // QSerialPort的readyRead()信号，只要有数据就抛出，自动执行serialPort_readyRead 函数
    QObject::connect(&serial, &QSerialPort::readyRead, this, &MainWindow::serial_slots_IRQHandler);

    // 调用pack_Send,会执行 on_file_send_boutton_clicked();
    //QObject::connect(this, &MainWindow::pack_Send, this, &MainWindow::on_file_send_boutton_clicked);

    //TIME1.start(100); // 100ms 后面逻辑中启动
    //TIME2.start(30);

    app_uart_init();

    parInit();

}

MainWindow::~MainWindow()
{
    delete ui;
}

// 应用程序 参数清零
void MainWindow::parInit(void)
{
    MeterNum_Cnt_Recv = 0;
    MeterNum_Cnt = 0;         // 有效表号总数量
    MeterNum_Cnt_index = 0;
}


// open uart device

void MainWindow::on_uart_button_clicked()
{
    QString uart_botton_text = ui->uart_button->text();

     if(uart_botton_text=="打开串口")  // 串口处于关闭状态
     {
        serial.setFlowControl(QSerialPort::NoFlowControl);    //设置串口流
        bool serial_state = serial.open(QIODevice::ReadWrite);//串口设置位读写
        if(serial_state ==false)
        {
            ui->textBrowser->append(tr("串口号被占用"));
        }
        else
        {
            ui->textBrowser->append(tr("串口打开成功!"));
            ui->uart_button->setText(tr("关闭串口"));
        }
     }
     else
     {
        ui->uart_button->setText(tr("打开串口"));
        ui->textBrowser->append(tr("关闭串口成功!"));
        serial.close();
        this->parInit();
        ui->file_send_boutton->setEnabled(true);
     }
}

void MainWindow::on_com_Box_currentIndexChanged(int index)
{
    Q_UNUSED(index);

    int current_index = ui->com_Box->currentIndex();  //获取当前下拉菜单的第几个项目
    QString com_Box_text = ui->com_Box->itemText(current_index);//获取当前项目的名称

    qDebug() << "当前串口为:" << com_Box_text << endl;

    serial.setPortName(com_Box_text);   //获取串口名
    ui->uart_button->setText("打开串口");  // 按钮显示字符
    serial.close();  // 默认关闭

}


void MainWindow::on_band_Box_currentIndexChanged(int index)
{
    Q_UNUSED(index);
    int current_index = ui->band_Box->currentIndex();  //获取当前在第几个项目
    QString band_Box_text = ui->band_Box->itemText(current_index);//获取当前在第几个项目的名称

    if(band_Box_text=="2400")
    {
        serial.setBaudRate(QSerialPort::Baud2400);
        qDebug("波特率设置2400成功");
    }
    else if(band_Box_text=="4800")
    {
        serial.setBaudRate(QSerialPort::Baud4800);
        qDebug("波特率设置4800成功");
    }
    else if(band_Box_text=="9600")
    {
        serial.setBaudRate(QSerialPort::Baud9600);
        qDebug("波特率设置9600成功");
    }
    else if(band_Box_text=="19200")
    {
        serial.setBaudRate(QSerialPort::Baud19200);
        qDebug("波特率设置19200成功");
    }
}

void MainWindow::on_checkBit_Box_currentIndexChanged(int index)
{
    Q_UNUSED(index);

    int current_index = ui->checkBit_Box->currentIndex();  //获取当前在第几个项目
    QString checkBit_Box_text = ui->checkBit_Box->itemText(current_index);//获取当前在第几个项目的名称
    if(checkBit_Box_text=="偶校验")
    {
         serial.setParity(QSerialPort::EvenParity);//设置偶校验
         qDebug("设置偶校验OK");
    }
    else if(checkBit_Box_text =="奇校验")
    {
         serial.setParity(QSerialPort::OddParity);//设置奇偶校验
         qDebug("设置奇校验OK");
    }
    else if(checkBit_Box_text== "无校验")
    {
        serial.setParity(QSerialPort::NoParity);//设置
        qDebug("设置无校验OK");
    }
}

void MainWindow::on_dataBit_Box_currentIndexChanged(int index)
{
    Q_UNUSED(index);
    int current_index = ui->dataBit_Box->currentIndex();  //获取当前在第几个项目
    QString dataBit_Box_text = ui->dataBit_Box->itemText(current_index);//获取当前在第几个项目的名称
    if(dataBit_Box_text=="7")
    {
       serial.setDataBits(QSerialPort::Data7); //设置数据位数
       qDebug("数据位数7设置");
    }
    else
    {
        serial.setDataBits(QSerialPort::Data8);
        qDebug("数据位数8设置");
    }
}



void MainWindow::on_stopBit_Box_currentIndexChanged(int index)
{
    Q_UNUSED(index);
    int current_index = ui->stopBit_Box->currentIndex();  //获取当前在第几个项目
    QString stopBit_Box_text = ui->stopBit_Box->itemText(current_index);//获取当前在第几个项目的名称
    if(stopBit_Box_text=="7")
    {
       serial.setStopBits(QSerialPort::OneStop);
       qDebug("设置1位停止位");
    }
    else
    {
       serial.setStopBits(QSerialPort::TwoStop);
       qDebug("设置2位停止位");
    }
}


// 抄表函数,按照dtl645-2007 协议组装数据
void MainWindow::meter_read( int meter_index)
{
    QByteArray s_buff_hex;
    unsigned char index =0;
    unsigned char crc =0;

    s_buff_hex.resize(200); // 定义200字节长度

    s_buff_hex[index++] = 0x68;
    s_buff_hex[index++] = meter_num[meter_index][5];
    s_buff_hex[index++] = meter_num[meter_index][4];
    s_buff_hex[index++] = meter_num[meter_index][3];
    s_buff_hex[index++] = meter_num[meter_index][2];
    s_buff_hex[index++] = meter_num[meter_index][1];
    s_buff_hex[index++] = meter_num[meter_index][0];
    s_buff_hex[index++]=0x68;

    for (int j = 0; j <7; j++)
    {
        qDebug("表号hex[%d] = 0x%02x",j,meter_num[meter_index][j]);
    }

    s_buff_hex[index++] = 0x11;  // 控制码
    s_buff_hex[index++] = 0X04;  // 数据与长度

    s_buff_hex[index++] = 0x33; //数据标识D0
    s_buff_hex[index++] = 0x33; //数据标识D1
    s_buff_hex[index++] = 0x34; //数据标识D2
    s_buff_hex[index++] = 0x33; //数据标识D3

    crc = mytool::cal_crc8(s_buff_hex,index);

    s_buff_hex[index++] =crc;
    s_buff_hex[index++] =0x16;

    if(serial.isOpen())
    {
        serial.write(s_buff_hex,index);
    }
    else
    {
         qDebug("串口未打开!");
    }
}


//装载 excel 表格文件 槽函数
void MainWindow::on_file_down_clicked()
{
    QString path =QFileDialog::getOpenFileName(this, tr("Open File"),"../",tr("Text files (*.xlsx *.xls)"));

    QString meter_total_str;

    qDebug()<<"filename : "<<path;

    if(path.isEmpty() ==false)
    {
       ui->pathTxT->setText(path);   //显示路径到框中
       QFile file(path);             //定义一个对象
       bool isok = file.open(QIODevice::ReadOnly); //打开文件路径下的文件

       if(isok == true)
       {
            qDebug()<<"打开表格OK";   

            MeterNum_Cnt_Recv = 0;

            QAxObject *excel = new QAxObject(this);//建立excel操作对象
            excel->setControl("Excel.Application");//连接Excel控件
            excel->setProperty("Visible", false);//不显示窗体看效果
            excel->setProperty("DisplayAlerts", false);//不显示警告看效果

            /*********获取COM文件的一种方式**********/
            QAxObject *workbooks = excel->querySubObject("WorkBooks");
            //获取工作簿(excel文件)集合
            workbooks->dynamicCall("Open(const QString&)", path);//path至关重要，获取excel文件的路径

            QAxObject *workbook = excel->querySubObject("ActiveWorkBook");
            QAxObject *worksheet = workbook->querySubObject("WorkSheets(int)",1);//访问excel中的工作表中第一个sheet
            QAxObject *usedRange = worksheet->querySubObject("UsedRange");//sheet的范围

            //获取打开excel的起始行数和列数和总共的行数和列数
            int intRowStart = usedRange->property("Row").toInt();//起始行数
            int intColStart = usedRange->property("Column").toInt(); //起始列数
            //起始行列号
            qDebug()<<"起始行 = "<<intRowStart;
            qDebug()<<"起始列 = "<<intColStart;

            QAxObject *rows, *columns;

            rows = usedRange->querySubObject("Rows");//行
            columns = usedRange->querySubObject("Columns");//列

            int intRowEnd = rows->property("Count").toInt();//结束行数
            int intColEnd = columns->property("Count").toInt();//结束列数

            //行数和列数
            qDebug()<<"结束行 = "<<intRowEnd;
            qDebug()<<"结束列 = "<<intColEnd;

            int total_Row = intRowEnd - intRowStart + 1 -1;
            int total_Col = intColEnd - intColStart + 1;

            qDebug()<<"有效总行 = "<<total_Row;
            qDebug()<<"有效总列 = "<<total_Col;

            // 有效表号个数(行数)
             MeterNum_Cnt = total_Row;
             MeterNum_Cnt_index = 2; // 取出来的时候数据整体往后偏移,可能与QT特性有关

             qDebug()<<"有效表号个数 = "<<MeterNum_Cnt;

             ui->textBrowser->append("表号如下:");

             QString MeterNumber;

            for(int i = intRowStart+1; i < total_Row + 2;i++)  // 有效行偏移量+1
            {
                QAxObject *cell = worksheet->querySubObject("Cells(int,int)", i, 6); // 第6列(提取有效数据:列)
                MeterNumber = cell->dynamicCall("Value2()").toString();//获取单元格内容
                qDebug()<<MeterNumber;
                ui->textBrowser->append(MeterNumber);

                unsigned char MeterNumHex[7];  //QString str = "252101100135";
                int num = 0;
                //12位表号字符串转换为hex
                for(int k = 0; k < MeterNumber.size(); k += 2)
                {
                    num = MeterNumber.mid(k,2).toUInt(nullptr,16); //每2个字符截取组合成16进制数
                    MeterNumHex[k/2] = num&0xFF;
                }   
#if 1
                for (int j = 0; j <7; j++)
                {
                    meter_num[i][j] = MeterNumHex[j];  //兼容7位表号地址
                    qDebug("表号hex[%d] = 0x%02x",j,meter_num[i][j]);
                }
#endif   
            }

            QString str_text = QString("档案中表计总数为:%1").arg(MeterNum_Cnt);
            ui->textBrowser->append(str_text);

            workbook->dynamicCall("Close (Boolean)", false);  //关闭文件
            excel->dynamicCall( "Quit(void)" );
            delete excel;
            file.close();     
       }
    }
}

// 点击开始测试 槽函数
// 一次抄所有的表
// 协议：DTL-645-2007
// 函数功能: 启动定时器,后续抄表报文由定时器信号溢出,触发槽函数pack_Send完成。
void MainWindow::on_file_send_boutton_clicked()
{
    if(serial.isOpen())
    {
        TIME1.start(100); // 100MS 溢出周期
        ui->file_send_boutton->setDisabled(true); // 按钮变灰
    }
    else
    {
        ui->textBrowser->append("串口未打开!");
    }
}


// 接收处理回调函数
void MainWindow::signal_serial_data_handler()
{
    //uint8_t crc ;  /*check sum*/
    //int real_frame_size = 0;
    //QByteArray rx_buff;
    //rx_buff.resize(100);  // 设置数组大小为100字节,并初始化
    MeterNum_Cnt_Recv++;// = 0;
    if(serial_RX_BUFF.at(0) == '\x68')
    {
        if(serial_RX_BUFF.at(8) == '\x91') // 读控制码
         {
             qDebug("累计接收总数 = %d",MeterNum_Cnt_Recv);
         }
    }
     serial_RX_BUFF.clear();
     rx_status = 0;

    //if(serial_RX_BUFF.data()[0] == 0x68)
    // crc = mytool::cal_crc8(serial_RX_BUFF,18);
    // qDebug()<< "crc校验为"<<crc<<" 校验通过！"<<endl;
    // qDebug("%d",serial_RX_BUFF.at(18));

    //if(crc == serial_RX_BUFF.at(18))
    //{
    //    qDebug()<< "crc校验为"<<crc<<" 校验通过！"<<endl;
    //}
    //real_frame_size = mytool::APP_FrameCMD_Strip(this->serial_RX_BUFF,this->serial_RX_BUFF.size(),rx_buff);
    //qDebug("received : %s",rx_buff.data());
    //ui->textBrowser->append(tr(rx_buff.toHex()));
    //cs = mytool::cal_crc8(serial_RX_BUFF,real_frame_size-2);
    //if(cs == rx_buff[real_frame_size-2])
    //qDebug()<< "crc校验为"<<cs<<" 校验通过！"<<endl;
}


/************************************************************
 * 定时器1 溢出后执行的槽函数
 *
 *
 ***********************************************************/
void MainWindow::timer_slots_IRQHandler()
{
      if(this->time1out<0xffff)
      {
        this->time1out++;
      }
      if( this->time1out>10)  //20 * 100ms = 2000ms
      {
          this->time1out = 0;
          TIME1.stop();

         if( MeterNum_Cnt_index < (MeterNum_Cnt + 2) )
         {
             QString mstr = QString("正在抄第%1只表...").arg(MeterNum_Cnt_index - 1);
             ui->textBrowser->append(mstr);
             qDebug("正在抄表...MeterNum_Cnt_index - 1  = %d",MeterNum_Cnt_index -1);

             // 执行抄表发送数据
             meter_read(MeterNum_Cnt_index);

             MeterNum_Cnt_index++;
             TIME1.start();
         }

          if( MeterNum_Cnt_index == (MeterNum_Cnt + 2) )
          {
              qDebug("停止抄表1...MeterNum_Cnt_index = [%d]",MeterNum_Cnt_index);
              MeterNum_Cnt_index++;
              TIME1.start();
          }

          if( MeterNum_Cnt_index == (MeterNum_Cnt + 3) )
          {
              qDebug("停止抄表2...MeterNum_Cnt_index = [%d]",MeterNum_Cnt_index);
              MeterNum_Cnt_index++;
              TIME1.start();
          }

          if( MeterNum_Cnt_index == (MeterNum_Cnt + 5) )
          {       
              if(MeterNum_Cnt == MeterNum_Cnt_Recv)
              {
                  QString mstr1 = QString("累计接收总数 %1").arg(MeterNum_Cnt_Recv);
                  ui->textBrowser->append(mstr1);
                  QMessageBox::warning(this,tr("测试情况"),tr("测试成功！"),QMessageBox::Yes);
                  ui->textBrowser->append("测试成功! Success!!!");
              }
              else
              {
                 ui->textBrowser->append("测试失败,实际表号与档案中不一致，请检查！!");
              }

              ui->file_send_boutton->setEnabled(true);
              //MeterNum_Cnt_Recv = 0;
              //MeterNum_Cnt_index = 0;
          }
      }
}


// 由串口接收 readyRead 驱动,自动执行
void MainWindow::serial_slots_IRQHandler()
{
    this->serial_RX_BUFF.append(serial.readAll());
    qDebug()<<"接收到表计返回的原始数据..."<<endl;
    this->time2out = 0;
    rx_status = 1; // busy
    // 启动定时器2,超时后自动处理接收的数据
    TIME2.start(200); // 200ms内可以保证数据已接收完成
    // 2400bps -> 24Bytes pre 100ms
}


// 定时器溢出后 自动执行此函数 用于串口接收
void MainWindow::timer2_slots_IRQHandler()
{
     if(this->serial_RX_BUFF.size()>13)
      {
         ui->textBrowser->append("接收:");
         ui->textBrowser->append(tr(this->serial_RX_BUFF.toHex())); //hex格式显示接收数据
         //TIME2.stop();
         signal_serial_data_handler(); // 做具体的协议解析 
     }
}


void MainWindow::on_actioninformation_triggered()
{
    QLabel *lab = new QLabel(0);
    QString Ltitle =  "软件版本";
    lab->setWindowTitle(Ltitle);
    lab->setGeometry(700,400,250,80);  //显示标签的坐标
    QFont  font ( "SimSun",12,50);
    lab->setFont(font);
    lab->setText("version V1.0");  // 标签显示内容
    lab->show();
}

void MainWindow::on_getMCUVersion_clicked()
{
    QByteArray s_buff;
    unsigned char index =0;
    unsigned char crc =0;
    s_buff.resize(30);
    s_buff[index++]=0x68;
    s_buff[index++]=0x99;
    s_buff[index++]=0x99;
    s_buff[index++]=0x99;
    s_buff[index++]=0x99;
    s_buff[index++]=0x99;
    s_buff[index++]=0x99;
    s_buff[index++]=0x68;
    s_buff[index++]=0x11;
    s_buff[index++]=0x04;
    s_buff[index++]=0x01;
    s_buff[index++]=0x00;
    s_buff[index++]=0x80;
    s_buff[index++]=0x04;

    if(serial.isOpen())
    {
        crc = mytool::cal_crc8(s_buff,index);
        s_buff[index++] =crc;
        s_buff[index++] =0x16;
        serial.write(s_buff,index);
    }
    else
    {
        ui->textBrowser->append("串口未打开!");
    }
}


void MainWindow::on_ClearLog_clicked()
{
    ui->textBrowser->clear();
}

